<script setup lang="ts">
import { ref, onMounted, reactive } from "vue"
import axios from "axios"
// 导入工具函数
import { applyMosaic, loadImageToCanvas, canvasToBlob } from "../utils/mosaicUtils"
import { loadModel, detectSensitiveAreas } from "../utils/modelUtils"
import { maskAllSensitiveText } from "../utils/ocrUtils"

// 状态管理
const fileInput = ref<HTMLInputElement | null>(null)
const canvas = ref<HTMLCanvasElement | null>(null)
const previewCanvas = ref<HTMLCanvasElement | null>(null)
const isModelLoading = ref(true)
const isProcessing = ref(false)
const isUploading = ref(false)
const message = ref("模型加载中，请稍候...")
const loadingProgress = ref(0)
// 上传状态
const uploadState = reactive({
  success: false,
  error: false,
  message: "",
})
// 模型相关
let model: any = null
// 加载模型
onMounted(async () => {
  try {
    // 使用工具函数加载模型
    model = await loadModel((msg, progress) => {
      message.value = msg
      if (progress !== undefined) {
        loadingProgress.value = progress
      }
    })
    
    isModelLoading.value = false
    message.value = "模型加载完成，可以上传图片"
  } catch (error) {
    console.error("模型加载失败:", error)
    message.value = "模型加载失败，请刷新页面重试"
  }
})
// 处理文件选择
const handleFileSelect = async (event: Event) => {
  const target = event.target as HTMLInputElement
  if (!target.files || target.files.length === 0) return
  
  const file = target.files[0]
  if (!file.type.startsWith("image/")) {
    message.value = "请选择图片文件"
    return
  }
  
  try {
    isProcessing.value = true
    message.value = "正在处理图片..."
    
    // 加载图片到Canvas
    if (canvas.value && previewCanvas.value) {
      await loadImageToCanvas(file, canvas.value, previewCanvas.value)
      
      // 检测并应用马赛克
      if (model && canvas.value) {
        await detectAndMaskSensitiveAreas()
      }
    }
    
    isProcessing.value = false
    message.value = "处理完成，可以上传或重新选择图片"
  } catch (error) {
    console.error("图片处理失败:", error)
    isProcessing.value = false
    message.value = "图片处理失败，请重试"
  }
}
// 检测并遮蔽敏感区域
const detectAndMaskSensitiveAreas = async () => {
  if (!model || !canvas.value) return
  
  // 在原图上应用马赛克
  const ctx = canvas.value.getContext("2d")
  if (!ctx) return
  
  // 1. 使用TensorFlow.js检测人脸（对应身份证头像）
  const sensitiveRegions = await detectSensitiveAreas(model, canvas.value)
  
  // 应用马赛克到每个检测到的区域
  sensitiveRegions.forEach(([x, y, width, height]) => {
    applyMosaic(ctx, x, y, width, height)
  })
  
  // 2. 使用OCR识别并马赛克处理身份证号码和车牌号
  message.value = "正在识别并处理身份证号码和车牌号..."
  
  try {
    // 使用Tesseract.js进行OCR识别并遮蔽敏感文本
    await maskAllSensitiveText(canvas.value, ctx)
  } catch (error) {
    console.error("OCR处理失败:", error)
  }
}
// 上传处理后的图片
const uploadImage = async () => {
  if (!canvas.value || isProcessing.value || isUploading.value) return
  
  try {
    isUploading.value = true
    message.value = "正在上传图片..."
    
    // 将Canvas转换为Blob
    const blob = await canvasToBlob(canvas.value)
    
    if (!blob) {
      throw new Error("图片转换失败")
    }
    
    // 创建FormData对象
    const formData = new FormData()
    formData.append("image", blob, "masked_image.jpg")
    
    // 发送到后端
    const response = await axios.post("/api/upload", formData, {
      headers: {
        "Content-Type": "multipart/form-data",
      },
    })
    
    isUploading.value = false
    uploadState.success = true
    uploadState.error = false
    uploadState.message = "图片上传成功"
    message.value = "图片上传成功"
    
    console.log("上传成功:", response.data)
  } catch (error) {
    console.error("上传失败:", error)
    isUploading.value = false
    uploadState.success = false
    uploadState.error = true
    uploadState.message = "图片上传失败，请重试"
    message.value = "图片上传失败，请重试"
  }
}
// 重新选择图片
const resetSelection = () => {
  if (fileInput.value) {
    fileInput.value.value = ""
  }
  
  // 清空Canvas
  if (canvas.value) {
    const ctx = canvas.value.getContext("2d")
    if (ctx) ctx.clearRect(0, 0, canvas.value.width, canvas.value.height)
  }
  
  if (previewCanvas.value) {
    const previewCtx = previewCanvas.value.getContext("2d")
    if (previewCtx) previewCtx.clearRect(0, 0, previewCanvas.value.width, previewCanvas.value.height)
  }
  
  // 重置状态
  uploadState.success = false
  uploadState.error = false
  uploadState.message = ""
  message.value = "请选择图片"
}
</script>
<template>
  <div class="image-mask-uploader">
    <h2>图片隐私脱敏工具</h2>
    
    <!-- 状态提示 -->
    <div class="status-message" :class="{ error: uploadState.error }">{{ message }}</div>
    
    <!-- 文件选择 -->
    <div class="file-selection">
      <!-- 隐藏原始文件输入框 -->
      <input 
        type="file" 
        id="fileInput"
        ref="fileInput" 
        accept="image/*" 
        @change="handleFileSelect" 
        :disabled="isModelLoading || isProcessing" 
        class="custom-file-input"
      />
      <!-- 自定义文件选择按钮 -->
      <label for="fileInput" class="custom-file-button">
        选择图片文件
      </label>
      <div class="button-group">
        <button
          @click="uploadImage"
          :disabled="isModelLoading || isProcessing || isUploading || !canvas || !canvas.width"
          class="primary-button"
        >
          上传脱敏图片
        </button>
        <button
          @click="resetSelection"
          :disabled="isModelLoading || isProcessing || isUploading || !canvas || !canvas.width"
        >
          重新选择
        </button>
      </div>
    </div>
    
    <!-- 加载指示器 -->
    <div v-if="isModelLoading || isProcessing || isUploading" class="loading-indicator">
      <div class="spinner"></div>
      <div>{{ message }}</div>
      <div v-if="isModelLoading && loadingProgress > 0" class="progress-container">
        <div class="progress-bar" :style="{ width: loadingProgress + '%' }"></div>
        <div class="progress-text">{{ loadingProgress }}%</div>
      </div>
    </div>
    
    <!-- 图片预览区域 -->
    <div class="image-preview-container" v-if="!isModelLoading">
      <div class="preview-section">
        <h3>原始图片</h3>
        <canvas ref="previewCanvas" class="preview-canvas"></canvas>
      </div>
      <div class="preview-section">
        <h3>脱敏后图片</h3>
        <canvas ref="canvas" class="main-canvas"></canvas>
      </div>
    </div>
    
    <!-- 说明信息 -->
    <div class="instructions">
      <h3>使用说明</h3>
      <ul>
        <li><span class="summary">头像处理：</span>支持自动识别身份证头像并应用马赛克</li>
        <li><span class="summary">身份证号识别：</span>使用OCR技术自动识别并模糊处理身份证号码</li>
        <li><span class="summary">车牌处理：</span>能够识别并自动脱敏车牌号码</li>
        <li><span class="summary">隐私保护：</span>所有处理均在本地完成，原始图片不会上传到服务器</li>
      </ul>
    </div>
  </div>
</template>

<style lang="less" scoped>
.image-mask-uploader {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;
  font-family: Arial, sans-serif;
  
  h2 {
    color: #333;
    margin-bottom: 20px;
    text-align: center;
  }
  
  .status-message {
    margin: 10px 0;
    padding: 10px;
    background-color: #f8f9fa;
    border-radius: 4px;
    text-align: center;
    
    &.error {
      background-color: #f8d7da;
      color: #721c24;
    }
  }
  
  .file-selection {
    margin: 20px 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    position: relative;
  }
  
  /* 隐藏原始文件输入框 */
  .custom-file-input {
    position: absolute;
    width: 0.1px;
    height: 0.1px;
    opacity: 0;
    overflow: hidden;
    z-index: -1;
  }
  
  /* 自定义文件选择按钮 */
  .custom-file-button {
    display: inline-block;
    padding: 12px 24px;
    background-color: #ff7d00;
    color: white;
    border-radius: 4px;
    cursor: pointer;
    font-size: 16px;
    font-weight: 500;
    text-align: center;
    transition: all 0.3s ease;
    border: none;
    outline: none;
  }
  
  .custom-file-button:hover {
    background-color: #ff9733;
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(255, 125, 0, 0.3);
  }
  
  .custom-file-button:active {
    transform: translateY(0);
    box-shadow: 0 2px 6px rgba(255, 125, 0, 0.3);
  }
  
  .custom-file-input:disabled + .custom-file-button {
    background-color: #ccc;
    cursor: not-allowed;
    transform: none;
    box-shadow: none;
  }
  
  .button-group {
    margin-top: 10px;
    display: flex;
    gap: 10px;
  }
  
  button {
    padding: 8px 16px;
    border: 1px solid #ddd;
    background-color: #f0f0f0;
    border-radius: 4px;
    cursor: pointer;
    font-size: 14px;
    
    &:disabled {
      opacity: 0.6;
      cursor: not-allowed;
    }
    
    &.active {
      background-color: #e6f7ff;
      border-color: #1890ff;
      color: #1890ff;
    }
    
    &.primary-button {
      background-color: #4caf50;
      color: white;
      border: none;
    }
  }
  
  .loading-indicator {
    display: flex;
    flex-direction: column;
    align-items: center;
    margin: 20px 0;
    
    .spinner {
      border: 4px solid rgba(0, 0, 0, 0.1);
      border-radius: 50%;
      width: 40px;
      height: 40px;
      border-top: 4px solid #4caf50;
      animation: spin 1s linear infinite;
      margin-bottom: 10px;
    }
  }
  
  @keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
  }
  
  .progress-container {
    width: 80%;
    height: 20px;
    background-color: #f0f0f0;
    border-radius: 10px;
    margin: 10px auto;
    position: relative;
    overflow: hidden;
    
    .progress-bar {
      height: 100%;
      background-color: #4caf50;
      border-radius: 10px;
      transition: width 0.3s ease;
    }
    
    .progress-text {
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      text-align: center;
      line-height: 20px;
      color: #fff;
      text-shadow: 0 0 2px rgba(0, 0, 0, 0.5);
      font-weight: bold;
    }
  }
  
  .loading-tips {
    margin-top: 10px;
    font-size: 12px;
    color: #666;
    font-style: italic;
  }
  
  .image-preview-container {
    display: flex;
    flex-wrap: wrap;
    gap: 20px;
    margin: 20px 0;
    justify-content: center;
    
    .preview-section {
      flex: 1;
      min-width: 300px;
      max-width: 500px;
      
      h3 {
        margin-top: 0;
        color: #555;
        text-align: center;
      }
    }
  }
  
  canvas {
    width: 100%;
    border: 1px solid #ddd;
    border-radius: 4px;
    background-color: #f8f9fa;
  }
  
  .selection-mode-hint {
    margin-top: 8px;
    padding: 8px;
    background-color: #e6f7ff;
    border-radius: 4px;
    text-align: center;
    font-size: 14px;
    color: #1890ff;
  }
  
  .upload-result {
    margin: 10px 0;
    padding: 10px;
    border-radius: 4px;
    text-align: center;
    
    &.success {
      background-color: #d4edda;
      color: #155724;
    }
    
    &.error {
      background-color: #f8d7da;
      color: #721c24;
    }
  }
  
  .instructions {
    margin-top: 30px;
    padding: 20px;
    background-color: #f8f9fa;
    border-radius: 8px;
    border-left: 4px solid #ff7d00;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
    text-align: left;
    
    h3 {
      margin-top: 0;
      margin-bottom: 15px;
      color: #333;
      font-size: 18px;
    }
    
    ul {
      padding-left: 20px;
      margin: 0;
      list-style-type: none;
      
      li {
        margin-bottom: 12px;
        line-height: 1.6;
        color: #555;
        position: relative;
        
        &:before {
          content: "•";
          color: #ff7d00;
          font-weight: bold;
          display: inline-block;
          width: 1em;
          margin-left: -1em;
        }
        
        .summary {
          font-weight: bold;
          color: #333;
        }
      }
    }
  }
}
</style>
